package de.g18.gruppe3.ldapinterface.service;

import java.util.ArrayList;
import java.util.List;

import de.g18.gruppe3.common.exception.ServiceException;
import de.g18.gruppe3.common.ldap.LDAPSynchronizationService;
import de.g18.gruppe3.common.ldap.OrganizationalUnitService;
import de.g18.gruppe3.common.ldap.UserService;
import de.g18.gruppe3.common.model.OrganizationalUnit;
import de.g18.gruppe3.common.model.User;
import de.g18.gruppe3.ldapinterface.service.provider.LDAPServiceProvider;

/**
 * Implementierung des {@link LDAPSynchronizationService}
 *
 * @author <a href="mailto:kevinhuber.kh@gmail.com">Kevin Huber</a>
 */
public class LDAPSynchronizationServiceImpl implements LDAPSynchronizationService {

    private static final LDAPServiceProvider SERVICE_PROVIDER = LDAPServiceProvider.getInstance();

    private static final OrganizationalUnitService ouService = SERVICE_PROVIDER.getOrganizationalUnitService();
    private static final UserService userService = SERVICE_PROVIDER.getUserService();


	@Override
	public void synchronize(List<User> aUserList) throws ServiceException {
	    List<User> ldapUser = userService.getAllUsers();
	    List<OrganizationalUnit> ldapOUs = ouService.getAllOrganizationalUnits();
	    List<OrganizationalUnit> syncOUs = extractOUsFromUsers(aUserList);

        // Benutzer entfernen die nicht in der Liste stehen
        List<User> usersToRemove = new ArrayList<User>();
        usersToRemove.addAll(ldapUser);
        usersToRemove.removeAll(aUserList);
        for (User user : usersToRemove) {
            userService.deleteUser(user);
        }

        // Organisationseinheiten entfernen die nicht in der Liste stehen
        List<OrganizationalUnit> ousToRemove = new ArrayList<OrganizationalUnit>();
        ousToRemove.addAll(ldapOUs);
        ousToRemove.removeAll(syncOUs);
        for (OrganizationalUnit ou : ousToRemove) {
            ouService.deleteOU(ou);
        }

        // Neue Organisationseinheiten anlegen
        List<OrganizationalUnit> ousToAdd = new ArrayList<OrganizationalUnit>();
        ousToAdd.addAll(syncOUs);
        ousToAdd.removeAll(ldapOUs);
        for (OrganizationalUnit ou : ousToAdd) {
            ouService.createOrganizationalUnit(ou);
        }

        // Neue Benutzer anlegen
        List<User> usersToAdd = new ArrayList<User>();
        usersToAdd.addAll(aUserList);
        usersToAdd.removeAll(ldapUser);
        for (User user : usersToAdd) {
            // OU aus AD laden (teil-persistierung des Users)
            OrganizationalUnit ou = ouService.getOrganizationalUnitByName(user.getOU().getName());
            user.setOU(ou);

            userService.createUser(user);
        }
	}

	private List<OrganizationalUnit> extractOUsFromUsers(List<User> aUserList) {
		List<OrganizationalUnit> result = new ArrayList<OrganizationalUnit>();
	    for (User user : aUserList) {
	    	if (result.contains(user.getOU())) {
	    		continue;
	    	}
	        result.add(user.getOU());
	    }
	    return result;
	}
}
